﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Globalization;
using System.Xml;
using System.Web;

namespace Nuane.Posterous
{
	internal static class Helper
	{
		public static string GetChildElementValue(XmlNode element, string childElementName, bool required)
		{
			XmlElement e = element[childElementName];
			if (e == null)
			{
				if (required)
					throw new PosterousException("Node not found.", PosterousExceptionStatus.ServerProtocolViolation);
				return null;
			}
			return e.InnerText;
		}

		public static string GetChildElementValue(XmlNode element, string childElementName)
		{
			return GetChildElementValue(element, childElementName, true);
		}

		public static string GetAttributeValue(XmlNode element, string attributeName)
		{
			XmlAttribute a = element.Attributes[attributeName];
			if (a == null)
				throw new PosterousException("Attribute not found.", PosterousExceptionStatus.ServerProtocolViolation);
			return a.InnerText;
		}

		public static int ToInt32(string value)
		{
			int n;
			if (!int.TryParse(value, out n))
				throw new PosterousException("Unparsable value.", PosterousExceptionStatus.ServerProtocolViolation);
			return n;
		}

		public static bool ToBoolean(string value)
		{
			bool n;
			if (!bool.TryParse(value, out n))
				throw new PosterousException("Unparsable value.", PosterousExceptionStatus.ServerProtocolViolation);
			return n;
		}

		// "Thu, 04 Jun 2009 01:33:43 -0700"
		public static DateTime ToDateTime(string value)
		{
			DateTime n;
			if (!DateTime.TryParseExact(value, "ddd, dd MMM yyyy HH:mm:ss zzz", CultureInfo.InvariantCulture, 0, out n))
				throw new PosterousException("Unparsable value.", PosterousExceptionStatus.ServerProtocolViolation);
			return n;
		}

		public static Uri ToUri(string value, bool allowEmpty)
		{
			if (string.IsNullOrEmpty(value))
			{
				if (!allowEmpty)
					throw new PosterousException("Unparsable value.", PosterousExceptionStatus.ServerProtocolViolation);
				return null;
			}

			Uri n;
			if (!Uri.TryCreate(value, UriKind.Absolute, out n))
				throw new PosterousException("Unparsable value.", PosterousExceptionStatus.ServerProtocolViolation);
			return n;
		}

		public static Uri ToUri(string value)
		{
			return ToUri(value, false);
		}

		public static string ToString(DateTime value)
		{
			return value.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss", CultureInfo.InvariantCulture);
		}

		public static string RemoveUnnecessaryEntities(string input)
		{
			StringBuilder sb = new StringBuilder();

			int pos = 0;
			while (true)
			{
				int s = input.IndexOf('&', pos);
				if (s < 0)
				{
					sb.Append(input, pos, input.Length - pos);
					break;
				}

				sb.Append(input, pos, s - pos);

				pos = input.IndexOf(';', s);
				if (pos < 0)
				{
					sb.Append("&amp;");
					sb.Append(input, s + 1, input.Length - s - 1);
					break;
				}

				int prev = input.LastIndexOf('&', pos);
				while (s != prev)
				{
					sb.Append("&amp;");
					int n = input.IndexOf('&', s + 1);
					sb.Append(input, s + 1, n - s - 1);
					s = n;
				}

				pos++;

				string entity = input.Substring(s, pos - s);
				string character = HttpUtility.HtmlDecode(entity);
				if (character != entity)
				{
					entity = HttpUtility.HtmlEncode(character);
					if (entity[0] == '&' && entity[1] == '#')
						entity = character;
				}
				sb.Append(entity);
			}

			return sb.ToString();
		}

		private static void Append(MemoryStream ms, string value)
		{
			byte[] data = Encoding.UTF8.GetBytes(value);
			ms.Write(data, 0, data.Length);
		}

		private static void AppendField(MemoryStream ms, string splitter, string name, string filename, string id, string contentType, byte[] value)
		{
			if (filename == null)
				filename = "";
			else
				filename = string.Format(CultureInfo.InvariantCulture, "; filename=\"{0}\"", filename);

			Append(ms, string.Format("--{0}\r\n", splitter));
			Append(ms, string.Format("Content-Type: {0}\r\n", contentType));
			if (id != null)
				Append(ms, string.Format("Content-Id: {0}\r\n", id));
			Append(ms, string.Format("Content-Disposition: form-data; name=\"{0}\"{1}\r\n", name, filename));
			Append(ms, "Content-Transfer-Encoding: binary\r\n");
			Append(ms, "\r\n");
			ms.Write(value, 0, value.Length);
		}

		public static void AppendEnd(MemoryStream ms, string splitter)
		{
			Append(ms, string.Format("--{0}--\r\n", splitter));
		}

		public static void AppendField(MemoryStream ms, string splitter, string name, string filename, byte[] value)
		{
			string contentType;
			string id = null;
			switch (Path.GetExtension(filename).ToLowerInvariant())
			{
				case ".jpg":
				case ".jpeg":
					id = name;
					contentType = "image/jpeg";
					break;
				case ".png":
					id = name;
					contentType = "image/png";
					break;
				case ".gif":
					id = name;
					contentType = "image/gif";
					break;
				default:
					contentType = "application/octet-stream";
					break;
			}

			AppendField(ms, splitter, name, filename, id, contentType, value);
		}

		public static void AppendField(MemoryStream ms, string splitter, string name, string value, Encoding encoding)
		{
			string contentType = "text/plain";
			if (encoding != Encoding.ASCII)
				contentType = string.Format("{0}; charset={1}", contentType, encoding.WebName);
			AppendField(ms, splitter, name, null, null, contentType, encoding.GetBytes(value));
		}

	}
}
